#ifndef __M_HOST_H__
#define __M_HOST_H__
#include <memory>
#include <unordered_map>
#include <string>
#include <iostream>
#include "mq_binding.hpp"
#include "mq_message.hpp"
#include "mq_queue.hpp"
#include "mq_exchange.hpp"


namespace mq{
    class VirtualHost{
    private:
        mq::ExchangeManager::ptr _memp;//交换机管理类句柄
        mq::MsgQueueManager::ptr _mqmp;//消息队列管理类句柄
        mq::MessageManager::ptr _mmp;//消息管理类句柄
        mq::BindingManager::ptr _mbmp;//绑定信息管理类句柄
        std::string _host_name;
    public:
        using ptr = std::shared_ptr<VirtualHost>;

        VirtualHost(const std::string& hostname,const std::string& basedir,const std::string& dbfile):_host_name(hostname){
            _memp = std::make_shared<ExchangeManager>(dbfile);
            _mqmp = std::make_shared<MsgQueueManager>(dbfile);
            _mmp = std::make_shared<MessageManager>(basedir);
            _mbmp = std::make_shared<BindingManager>(dbfile);

            //因为消息的恢复不仅仅需要管理类还需要底层数据
            //而数据都是存储在队列中的，所以需要恢复队列，再在队列中添加恢复消息

            mq::QueueMap qm = _mqmp->AllQueue();
            for(auto& q : qm){
                _mmp->initQueue(q.first);
            }
        }

//创建交换机
        bool declareExchange(const std::string& ename,mq::ExchangeType etype,  
                            bool edurable,bool eauto_delete,
                            const google::protobuf::Map<std::string,std::string>& eargs){
            return _memp->declareExchange(ename,etype,edurable,eauto_delete,eargs);
        }   
//删除交换机
        bool deleteExchange(const std::string& ename){
            //删除交换机的同时要删除交换机相关绑定信息
            //并不用删除相关队列因为可能一个队列绑定多个交换机
            _mbmp->removeExchangeBindings(ename);

            //句柄再调用底层删除交换机
            return _memp->deleteExchange(ename);
        } 
//获取交换机 
        mq::Exchange::ptr selectExchange(const std::string& ename){
            return _memp->selectExchange(ename); 
        }

//判断交换机是否存在
        bool existsExchange(const std::string& ename){
            return _memp->exists(ename);
        }


    
//创建队列
        bool declareQueue(const std::string& qname,
            bool qdurable,
            bool qexclusive,
            bool qauto_delete,
            const google::protobuf::Map<std::string,std::string>& qargs){
//直接调用句柄中的声明创建队列即可
            _mmp->initQueue(qname);
            return _mqmp->declareQueue(qname,qdurable,qexclusive,qauto_delete,qargs);
        }

//删除队列
        bool deleteQueue(const std::string& qname){
            //删除队列的同时要删除队列中的消息以及绑定信息，因为他们已经无用了
            //1. 消息句柄删除队列中的消息
            _mmp->destroyQueueMessage(qname);
            //2. 绑定信息句柄删除相关队列的绑定信息
            _mbmp->removeQueueBindings(qname);
            return _mqmp->deleteQueue(qname);
        }

        QueueMap allQueues(){
            return _mqmp->AllQueue();
        }

//判断队列是否存在
        bool existsQueue(const std::string& qname){
            return _mqmp->exists(qname);
        }

//绑定队列和交换机
        bool bind(const std::string& ename,const std::string& qname,
                    const std::string& key){
            //对于bind绑定操作，需要注意的是，绑定的前提是 绑定的队列和交换机一定要存在
            //所以需要先进行判断

            //1. 交换机
            mq::Exchange::ptr mep = _memp->selectExchange(ename);
            //当他查找不到时就会返回第一个空的，所以判断即可知道是否存在
            if(mep.get() == nullptr){
                DLOG("进行队列绑定失败，交换机%s不存在",ename.c_str());
                return false;
            }

            //2. 队列
            mq::MsgQueue::ptr mqp = _mqmp->selectQueue(qname);
            if(mqp.get() == nullptr){
                DLOG("进行队列绑定失败，队列%s不存在",qname.c_str());
                return false;
            }

// 其中绑定信息是否持久化，需要队列和交换机都保持持久化，绑定才持久哈
            return _mbmp->bind(ename,qname,key,mep->durable && mqp->durable);
        }

//解绑
        bool unbind(const std::string& ename,const std::string& qname){
            return _mbmp->unbind(ename,qname);
        }


//判断绑定信息是否存在
        bool existsBinding(const std::string& ename,const std::string& qname){
            return _mbmp->exists(ename,qname);
        }

//获取交换机的所有绑定信息：队列
        MsgQueueBindingMap exchangeBindings(const std::string& ename){
            return _mbmp->getExchangeBindings(ename);//直接调用底层获取即可
        }

//发布消息（生产）
        bool basicPublish(const std::string& qname,BasicProperties* bp,const std::string& body){
            //对于推送消息，他的前提是保证消息的队列存在
            //判断队列是否存在，方法和前面的是一样的
            MsgQueue::ptr mqp = _mqmp->selectQueue(qname);
            if(mqp.get() == nullptr){
                DLOG("进行推送消息失败，队列%s不存在",qname.c_str());
                return false;
            }

            //此处的持久化设置为mqp->durable是因为其虽然是队列中的持久化但同时也是表示的是消息的持久化，其中在创建队列时就明确了内部消息的是否持久化他们是相同的！
            return _mmp->insert(qname,bp,body,mqp->durable);
        }

//获取消息（消费）：
        mq::MessagePtr basicConsume(const std::string& qname){
            return _mmp->front(qname);
        }



//消息确认（删除
        void basicAck(const std::string& qname,const std::string& msg_id){
            return _mmp->ack(qname,msg_id);
        }

        void clear(){
            _mmp->clear();
            _mqmp->clear();
            _mbmp->clear();
            _memp->clear();
        }
    };
}
#endif